package pit.com.ordermobilesystem.imageutil;

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;
import pit.com.ordermobilesystem.R;
import pit.com.ordermobilesystem.constant.OrderConstant;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;




/**
 * This class wraps up completing some arbitrary long running work when loading a bitmap to an
 * ImageView. It handles things like using a memory and disk cache, running the work in a background
 * thread and setting a placeholder image.
 */
public abstract class ImageWorker {
    private static final String TAG = "ImageWorker";
    private static final int FADE_IN_TIME = 200;

    protected static ImageCache mImageCache;
    private Bitmap mLoadingBitmap;
    private boolean mFadeInBitmap = false;
    private boolean mExitTasksEarly = false;
    private boolean offlineMode=false;
    private Bitmap mErrorBitmap;
    public int mImageWidth;
    public int mImageHeight;    
    protected Context mContext;
    public boolean isRoundConner=false;
   

    
    public boolean isRoundConner() {
		return isRoundConner;
    }

    public void setRoundConner(boolean isRoundConner) {
		this.isRoundConner = isRoundConner;
    }
    
    protected ImageWorker(Context context) {
        mContext = context;
        if(mImageCache==null){
        	mImageCache=new ImageCache(context,context.getString(R.string.directory));
        }
    }

    /**
     * Set placeholder bitmap that shows when the the background thread is running.
     *
     * @param resId
     */
    public void setErrorImage(int resId) {
        mErrorBitmap = BitmapFactory.decodeResource(mContext.getResources(), resId);
    }    

    
    /**
     * Set placeholder bitmap that shows when the the background thread is running.
     *
     * @param bitmap
     */
    public void setErrorImage(Bitmap bitmap) {
    	mErrorBitmap = bitmap;
    }    
    
    public boolean isOfflineMode() {
	return offlineMode;
}



public void setOfflineMode(boolean offlineMode) {
	this.offlineMode = offlineMode;
}



/**
     * Load an image specified by the data parameter into an ImageView (override
     * {@link ImageWorker#processBitmap(Object)} to define the processing logic). A memory and disk
     * cache will be used if an {@link ImageCache} has been set using
     * {@link ImageWorker#setImageCache(ImageCache)}. If the image is found in the memory cache, it
     * is set immediately, otherwise an {@link AsyncTask} will be created to asynchronously load the
     * bitmap.
     *
     * @param data The URL of the image to download.
     * @param imageView The ImageView to bind the downloaded image to.
     */
    public void loadImage(Object data, ImageView imageView) {
    	String url=String.valueOf(data);
    	if(url.contains("http://") || url.contains("https://") || url.contains("www") || url.contains("/sdcard") ){

    		
    	}else{
    		if(OrderConstant.SERVER_IMAGE_PORT.equals("")){
    			url="http://"+OrderConstant.SERVER_IMAGE+"/"+OrderConstant.NAME_SERVICE+"/"+OrderConstant.IMAGE_PATH+"/"+url;
    		}else{
    			url="http://"+OrderConstant.SERVER_IMAGE+":"+OrderConstant.SERVER_IMAGE_PORT+"/"+OrderConstant.NAME_SERVICE+"/"+OrderConstant.IMAGE_PATH+"/"+url;
    		}
    		
    	}        
    	Bitmap bitmap = null;

        if (mImageCache != null) {
            bitmap = mImageCache.getBitmapFromMemCache(String.valueOf(url));
        }

        if (bitmap != null) {
                // Bitmap found in memory cache
            	if(isRoundConner){
            		
            		 imageView.setImageBitmap(ImageHelper.getRoundedCornerBitmap(bitmap, imageView.getWidth()));
            	}else{
            		 imageView.setImageBitmap(bitmap);
            	}
        } else if (cancelPotentialWork(url, imageView)) {

	            final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
	            final AsyncDrawable asyncDrawable =
	                    new AsyncDrawable(mContext.getResources(), mLoadingBitmap, task);
	            imageView.setImageDrawable(asyncDrawable);
	            task.execute(url);
        }
    }

	public void saveImage(File f, byte[] data) {
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(f);
			fos.write(data);
			fos.close();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}  
	
    /**
     * Decode and sample down a bitmap from a file to the requested width and height.
     *
     * @param filename The full path of the file to decode
     * @param reqWidth The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
     *         that are equal to or greater than the requested width and height
     */
    public static synchronized Bitmap decodeSampledBitmapFromFile(String filename,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filename, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filename, options);
    }	
	
    
    /**
     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
     * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
     * the closest inSampleSize that will result in the final decoded bitmap having a width and
     * height equal to or larger than the requested width and height. This implementation does not
     * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but
     * results in a larger bitmap which isn't as useful for caching purposes.
     *
     * @param options An options object with out* params already populated (run through a decode*
     *            method with inJustDecodeBounds==true
     * @param reqWidth The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            if (width > height) {
                inSampleSize = Math.round((float) height / (float) reqHeight);
            } else {
                inSampleSize = Math.round((float) width / (float) reqWidth);
            }

            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger
            // inSampleSize).

            final float totalPixels = width * height;

            // Anything more than 2x the requested pixels we'll sample down
            // further.
            final float totalReqPixelsCap = reqWidth * reqHeight * 2;

            while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
                inSampleSize++;
            }
        }
        return inSampleSize;
    }   
    
    public boolean downloadImage(String data,int mImageWidth,int mImageHeight){
            final String dataString = String.valueOf(data);
            Bitmap bitmap = null;
            final File cacheDir =  mImageCache.getmDiskCache().getmCacheDir();

            final DiskLruCache cache =DiskLruCache.openCache(mContext, cacheDir, 10 * 1024 * 1024);
            final File cacheFile = new File(cache.createFilePath(data));
            // If the image cache is available and this task has not been cancelled by another
            // thread and the ImageView that was originally bound to this task is still bound back
            // to this task and our "exit early" flag is not set then try and fetch the bitmap from
            // the cache
            if (mImageCache != null ) {
                bitmap = mImageCache.getBitmapFromDiskCache(dataString);
            }

            // If the bitmap was not found in the cache and this task has not been cancelled by
            // another thread and the ImageView that was originally bound to this task is still
            // bound back to this task and our "exit early" flag is not set, then call the main
            // process method (as implemented by a subclass)
            if (bitmap == null ) {
        	    
                ImageUtils.disableConnectionReuseIfNecessary();
                HttpURLConnection urlConnection = null;
                BufferedOutputStream out = null;

                try {
                    final URL url = new URL(dataString);
                    urlConnection = (HttpURLConnection) url.openConnection();
                    urlConnection.setConnectTimeout(30000);
                    final InputStream in =
                            new BufferedInputStream(urlConnection.getInputStream(), ImageUtils.IO_BUFFER_SIZE);
                    out = new BufferedOutputStream(new FileOutputStream(cacheFile), ImageUtils.IO_BUFFER_SIZE);

                    int b;
                    while ((b = in.read()) != -1) {
                        out.write(b);
                    }

                } catch (final IOException e) {
                    Log.e(TAG, "Error in downloadBitmap - " + e);
                    return false;
                } finally {
                    if (urlConnection != null) {
                        urlConnection.disconnect();
                    }
                    if (out != null) {
                        try {
                            out.close();
                        } catch (final IOException e) {
                            Log.e(TAG, "Error in downloadBitmap - " + e);
                        }
                    }
                }   
                if (cacheFile != null) {
                    // Return a sampled down version
                     Bitmap image=decodeSampledBitmapFromFile(cacheFile.toString(), mImageWidth, mImageHeight);
     				 ByteArrayOutputStream dataImage = new ByteArrayOutputStream();
     				 image.compress(Bitmap.CompressFormat.JPEG, 60, dataImage);
     				 byte[] byteData = dataImage.toByteArray();                     
                     saveImage(cacheFile,byteData);
                     return true;
                }                    
                return false;
            }else{
        	    return true;
            }

    
    }

	
    /**
     * Set placeholder bitmap that shows when the the background thread is running.
     *
     * @param bitmap
     */
    public void setLoadingImage(Bitmap bitmap) {
        mLoadingBitmap = bitmap;
    }

    /**
     * Set placeholder bitmap that shows when the the background thread is running.
     *
     * @param resId
     */
    public void setLoadingImage(int resId) {
        mLoadingBitmap = BitmapFactory.decodeResource(mContext.getResources(), resId);
    }


    public ImageCache getImageCache() {
        return mImageCache;
    }

    /**
     * If set to true, the image will fade-in once it has been loaded by the background thread.
     *
     * @param fadeIn
     */
    public void setImageFadeIn(boolean fadeIn) {
        mFadeInBitmap = fadeIn;
    }

    public void setExitTasksEarly(boolean exitTasksEarly) {
        mExitTasksEarly = exitTasksEarly;
    }

    /**
     * Subclasses should override this to define any processing or work that must happen to produce
     * the final bitmap. This will be executed in a background thread and be long running. For
     * example, you could resize a large bitmap here, or pull down an image from the network.
     *
     * @param data The data to identify which image to process, as provided by
     *            {@link ImageWorker#loadImage(Object, ImageView)}
     * @return The processed bitmap
     */
    protected abstract Bitmap processBitmap(Object data);

    public static void cancelWork(ImageView imageView) {
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
        if (bitmapWorkerTask != null) {
            bitmapWorkerTask.cancel(true);
        }
    }

    /**
     * Returns true if the current work has been canceled or if there was no work in
     * progress on this image view.
     * Returns false if the work in progress deals with the same data. The work is not
     * stopped in that case.
     */
    public static boolean cancelPotentialWork(Object data, ImageView imageView) {
        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (bitmapWorkerTask != null) {
            final Object bitmapData = bitmapWorkerTask.data;
            if (bitmapData == null || !bitmapData.equals(data)) {
                bitmapWorkerTask.cancel(true);
            } else {
                // The same work is already in progress.
                return false;
            }
        }
        return true;
    }

    /**
     * @param imageView Any imageView
     * @return Retrieve the currently active work task (if any) associated with this imageView.
     * null if there is no such task.
     */
    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
        if (imageView != null) {
            final Drawable drawable = imageView.getDrawable();
            if (drawable instanceof AsyncDrawable) {
                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                return asyncDrawable.getBitmapWorkerTask();
            }
        }
        return null;
    }

    /**
     * The actual AsyncTask that will asynchronously process the image.
     */
    private class BitmapWorkerTask extends AsyncTask<Object, Void, Bitmap> {
        private Object data;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapWorkerTask(ImageView imageView) {
            imageViewReference = new WeakReference<ImageView>(imageView);
        }

        /**
         * Background processing.
         */
        @Override
        protected Bitmap doInBackground(Object... params) {
            data = params[0];
            final String dataString = String.valueOf(data);
            Bitmap bitmap = null;

            // If the image cache is available and this task has not been cancelled by another
            // thread and the ImageView that was originally bound to this task is still bound back
            // to this task and our "exit early" flag is not set then try and fetch the bitmap from
            // the cache
            if (mImageCache != null && !isCancelled() && getAttachedImageView() != null
                    && !mExitTasksEarly) {
                bitmap = mImageCache.getBitmapFromDiskCache(dataString);
            }

            // If the bitmap was not found in the cache and this task has not been cancelled by
            // another thread and the ImageView that was originally bound to this task is still
            // bound back to this task and our "exit early" flag is not set, then call the main
            // process method (as implemented by a subclass)
            if (bitmap == null && !isCancelled() && getAttachedImageView() != null
                    && !mExitTasksEarly && !offlineMode) {
                bitmap = processBitmap(params[0]);
            }

            // If the bitmap was processed and the image cache is available, then add the processed
            // bitmap to the cache for future use. Note we don't check if the task was cancelled
            // here, if it was, and the thread is still running, we may as well add the processed
            // bitmap to our cache as it might be used again in the future
            if (bitmap != null && mImageCache != null) {
                mImageCache.addBitmapToCache(dataString, bitmap);
            }

            return bitmap;
        }

        /**
         * Once the image is processed, associates it to the imageView
         */
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            // if cancel was called on this task or the "exit early" flag is set then we're done
            if (isCancelled() || mExitTasksEarly) {
                bitmap = null;
            }

            final ImageView imageView = getAttachedImageView();
            if (bitmap != null && imageView != null) {
                setImageBitmap(imageView, bitmap);
            }else{
            	if(mErrorBitmap!=null && imageView != null){
            		setImageBitmap(imageView,mErrorBitmap);
            	}            	
            }
        }

        /**
         * Returns the ImageView associated with this task as long as the ImageView's task still
         * points to this task as well. Returns null otherwise.
         */
        private ImageView getAttachedImageView() {
            final ImageView imageView = imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

            if (this == bitmapWorkerTask) {
                return imageView;
            }

            return null;
        }
    }

    /**
     * A custom Drawable that will be attached to the imageView while the work is in progress.
     * Contains a reference to the actual worker task, so that it can be stopped if a new binding is
     * required, and makes sure that only the last started worker process can bind its result,
     * independently of the finish order.
     */
    private static class AsyncDrawable extends BitmapDrawable {
        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

        public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) {
            super(res, bitmap);

            bitmapWorkerTaskReference =
                new WeakReference<BitmapWorkerTask>(bitmapWorkerTask);
        }

        public BitmapWorkerTask getBitmapWorkerTask() {
            return bitmapWorkerTaskReference.get();
        }
    }

    /**
     * Called when the processing is complete and the final bitmap should be set on the ImageView.
     *
     * @param imageView
     * @param bitmap
     */
    private void setImageBitmap(ImageView imageView, Bitmap bitmap) {
        if (mFadeInBitmap) {
            // Transition drawable with a transparent drwabale and the final bitmap
            if(mLoadingBitmap!=null){
	        	final TransitionDrawable td =
	                    new TransitionDrawable(new Drawable[] {
	                            new ColorDrawable(android.R.color.transparent),
	                            new BitmapDrawable(mContext.getResources(), bitmap)
	                    });
	
	            
	            imageView.setImageDrawable( new BitmapDrawable(mContext.getResources(), mLoadingBitmap));
	            imageView.setImageDrawable(td);
	            td.startTransition(FADE_IN_TIME);
            }else{
            	if(imageView.getDrawable() instanceof AnimationDrawable){
		            final AnimationDrawable animation=(AnimationDrawable) imageView.getDrawable();
		            animation.stop();
		            imageView.setTag(null);
            	}
            	imageView.setImageBitmap(bitmap);
            }
        } else {
            imageView.setImageBitmap(bitmap);
        }
    }

    public static void clearMemoryCache(){
    	if(mImageCache!=null)  	mImageCache.clearMemoryCache();
    }
    /**
     * A very simple adapter for use with ImageWorker class and subclasses.
     */
    public static abstract class ImageWorkerAdapter {
        public abstract Object getItem(int num);
        public abstract int getSize();
    }
    
	public String copyBitmapToDriveCached(Bitmap bitmap,String url_dest) throws IOException {
		
		File dst = mImageCache.getFile(url_dest);
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(dst);
			bitmap.compress(Bitmap.CompressFormat.JPEG, 60, fos);
			fos.flush();
			fos.close();

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    return dst.getPath();
	}     
}
